package beanstao.util.reflect;

import java.lang.annotation.Annotation;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.lang.StringUtils;
import org.dom4j.Element;
import org.dom4j.Node;

import beanstao.util.Util;
import beanstao.util.collections.Pair;
import beanstao.util.exception.technical.util.reflect.FailToCastObjectException;
import beanstao.util.exception.technical.util.reflect.FailToGetValueException;
import beanstao.util.exception.technical.util.reflect.FailToSetValueException;
import beanstao.util.exception.technical.util.reflect.ReflectException;
import beanstao.util.interfaces.ITypeExtractor;
import beanstao.util.log.LogHelper;
import beanstao.util.type.Castors;

/**
 * 包裹了 Class<?>， 提供了更多的反射方法
 * 
 * @param <T>
 */
public class Mirror<T>
{
	private static class DefaultITypeExtractor implements ITypeExtractor
	{
		public Class<?>[] extract(Mirror<?> mirror)
		{
			List<Class<?>> re = new ArrayList<Class<?>>(5);
			re.add(mirror.getType());
			if (mirror.klass.isEnum())
				re.add(Enum.class);
			else if (mirror.klass.isArray())
				re.add(Array.class);
			else if (mirror.isString())
				re.add(String.class);
			else if (mirror.is(Class.class))
				re.add(Class.class);
			else if (mirror.is(Mirror.class))
				re.add(Mirror.class);
			else if (mirror.isStringLike())
				re.add(CharSequence.class);
			else if (mirror.isNumber())
			{
				re.add(mirror.getType());
				re.add(Number.class);
			}
			else if (mirror.isBoolean())
				re.add(Boolean.class);
			else if (mirror.isChar())
				re.add(Character.class);
			else if (mirror.isOf(Map.class))
				re.add(Map.class);
			else if (mirror.isOf(Collection.class))
				re.add(Collection.class);
			else if (mirror.isOf(Calendar.class))
				re.add(Calendar.class);
			else if (mirror.isOf(Timestamp.class))
				re.add(Timestamp.class);
			else if (mirror.isOf(java.sql.Date.class))
				re.add(java.sql.Date.class);
			else if (mirror.isOf(java.sql.Time.class))
				re.add(java.sql.Time.class);
			else if (mirror.isOf(java.util.Date.class))
				re.add(java.util.Date.class);
			re.add(Object.class);
			return re.toArray(new Class<?>[re.size()]);
		}
	}

	private final static DefaultITypeExtractor defaultITypeExtractor = new DefaultITypeExtractor();

	/**
	 * 快速从一个XML节点中提取Key, 并提取类名，类名创建一个对象与对象名
	 * 
	 * @param <R>
	 * @param node
	 * @return
	 */
	public static <R> Pair<String, R> klassbuilder(Node node)
	{
		if ((node == null) || !(node instanceof Element))
			return null;
		Element subEle = (Element) node;
		String name = subEle.attributeValue("key");
		R obj = null;
		try
		{
			obj = Mirror.builder(subEle.attributeValue("class"));
		}
		catch (Exception e)
		{
			LogHelper.logError(node, String.format("Mirror创建对象出错。数据源:%s; 异常：%s", node.asXML(), e.getMessage()));
		}
		return Pair.ME(name, obj);
	}

	/**
	 * 快速简单创建一个无参数构造函数的对象
	 * 
	 * @param <T>
	 * @param klassName
	 * @return
	 * @throws ClassNotFoundException
	 * @throws IllegalArgumentException
	 * @throws InstantiationException
	 * @throws IllegalAccessException
	 * @throws InvocationTargetException
	 */
	@SuppressWarnings("unchecked")
	public static <T> T builder(String klassName) throws ClassNotFoundException, IllegalArgumentException, InstantiationException, IllegalAccessException, InvocationTargetException
	{
		Class<?> klass = Class.forName(klassName);
		T myObj = (T) Mirror.me(klass).born(new Object[] {});
		return myObj;
	}

	/**
	 * 包裹一个类
	 * 
	 * @param classOfT 类
	 * @return Mirror
	 */
	public static <T> Mirror<T> me(Class<T> classOfT)
	{
		return null == classOfT ? null : new Mirror<T>(classOfT).setITypeExtractor(defaultITypeExtractor);
	}

	/**
	 * 生成一个对象的 Mirror
	 * 
	 * @param obj 对象。
	 * @return Mirror， 如果 对象 null，则返回 null
	 */
	@SuppressWarnings("unchecked")
	public static <T> Mirror<T> me(T obj)
	{
		return null == obj ? null : (Mirror<T>) me(obj.getClass());
	}

	/**
	 * 包裹一个类，并设置自定义的类型提炼逻辑
	 * 
	 * @param classOfT
	 * @param typeExtractor
	 * @return Mirror .lang.ITypeExtractor
	 */
	public static <T> Mirror<T> me(Class<T> classOfT, ITypeExtractor typeExtractor)
	{
		return null == classOfT ? null : new Mirror<T>(classOfT).setITypeExtractor(typeExtractor == null ? defaultITypeExtractor : typeExtractor);
	}

	private final Class<T> klass;

	private ITypeExtractor typeExtractor;

	/**
	 * 设置自己的类型提炼逻辑
	 * 
	 * @param typeExtractor
	 * @return Mirror .lang.ITypeExtractor
	 */
	public Mirror<T> setITypeExtractor(ITypeExtractor typeExtractor)
	{
		this.typeExtractor = typeExtractor;
		return this;
	}

	private Mirror(Class<T> classOfT)
	{
		this.klass = classOfT;
	}

	/**
	 * 根据构造函数参数，创建一个对象。
	 * 
	 * @param args 构造函数参数
	 * @return 新对象
	 * @throws InvocationTargetException
	 * @throws IllegalAccessException
	 * @throws InstantiationException
	 * @throws IllegalArgumentException
	 */
	public T born(Object... args) throws IllegalArgumentException, InstantiationException, IllegalAccessException, InvocationTargetException
	{
		if (args.length == 0)
			return this.bornEvalNullArgs(args);
		else
			return this.bornEvalWithArgs(args);
	}

	/**
	 * 根据名称获取一个 Getter。
	 * <p>
	 * 比如，你想获取 abc 的 getter ，那么优先查找 getAbc()，如果没有则查找isAbc()，最后才是查找 abc()。
	 * 
	 * @param fieldName
	 * @return 方法
	 * @throws NoSuchMethodException 没有找到 Getter
	 */
	public Method getGetter(String fieldName) throws NoSuchMethodException
	{
		try
		{
			String fn = StringUtils.capitalize(fieldName);
			try
			{
				try
				{
					return this.klass.getMethod("get" + fn);
				}
				catch (NoSuchMethodException e)
				{
					Method m = this.klass.getMethod("is" + fn);
					if (!Mirror.me(m.getReturnType()).isBoolean())
						throw new NoSuchMethodException();
					return m;
				}
			}
			catch (NoSuchMethodException e)
			{
				return this.klass.getMethod(fieldName);
			}
		}
		catch (Exception e)
		{
			throw new ReflectException(NoSuchMethodException.class.getSimpleName() + String.format("Fail to find getter for [%s]->[%s]", this.klass.getName(), fieldName));
		}
	}

	/**
	 * 根据字段获取一个 Getter。
	 * <p>
	 * 比如，你想获取 abc 的 getter ，那么优先查找 getAbc()，如果 没有，则查找 abc()。
	 * 
	 * @param field
	 * @return 方法
	 * @throws NoSuchMethodException 没有找到 Getter
	 */
	public Method getGetter(Field field) throws NoSuchMethodException
	{
		try
		{
			try
			{
				String fn = StringUtils.capitalize(field.getName());
				if (Mirror.me(field.getType()).isBoolean())
					return this.klass.getMethod("is" + fn);
				else
					return this.klass.getMethod("get" + fn);
			}
			catch (NoSuchMethodException e)
			{
				return this.klass.getMethod(field.getName());
			}
		}
		catch (Exception e)
		{
			throw new ReflectException(NoSuchMethodException.class.getSimpleName() + String.format("Fail to find getter for [%s]->[%s]", this.klass.getName(), field.getName()));
		}
	}

	/**
	 * 根据一个字段获取 Setter
	 * <p>
	 * 比如，你想获取 abc 的 setter ，那么优先查找 setAbc(T abc)，如果 没有，则查找 abc(T abc)。
	 * 
	 * @param field 字段
	 * @return 方法
	 * @throws NoSuchMethodException 没找到 Setter
	 */
	public Method getSetter(Field field) throws NoSuchMethodException
	{
		try
		{
			try
			{
				return this.klass.getMethod("set" + StringUtils.capitalize(field.getName()), field.getType());
			}
			catch (Exception e)
			{
				try
				{
					if (field.getName().startsWith("is") && Mirror.me(field.getType()).isBoolean())
						return this.klass.getMethod("set" + field.getName().substring(2), field.getType());
				}
				catch (Exception e1)
				{
				}
				return this.klass.getMethod(field.getName(), field.getType());
			}
		}
		catch (Exception e)
		{
			throw new ReflectException(NoSuchMethodException.class.getSimpleName() + String.format("Fail to find setter for [%s]->[%s]", this.klass.getName(), field.getName()));
		}
	}

	/**
	 * 根据一个字段名和字段类型获取 Setter
	 * 
	 * @param fieldName 字段名
	 * @param paramType 字段类型
	 * @return 方法
	 * @throws NoSuchMethodException 没找到 Setter
	 */
	public Method getSetter(String fieldName, Class<?> paramType) throws NoSuchMethodException
	{
		try
		{
			String setterName = "set" + StringUtils.capitalize(fieldName);
			try
			{
				return this.klass.getMethod(setterName, paramType);
			}
			catch (Exception e)
			{
				try
				{
					return this.klass.getMethod(fieldName, paramType);
				}
				catch (Exception e1)
				{
					Mirror<?> type = Mirror.me(paramType);
					for (Method method : this.klass.getMethods())
						if (method.getParameterTypes().length == 1)
							if (method.getName().equals(setterName) || method.getName().equals(fieldName))
								if ((null == paramType) || type.canCastToDirectly(method.getParameterTypes()[0]))
									return method;
					throw new Exception();
				}
			}
		}
		catch (Exception e)
		{
			throw new ReflectException(NoSuchMethodException.class.getSimpleName() + String.format("Fail to find setter for [%s]->[%s(%s)]", this.klass.getName(), fieldName, paramType.getName()));
		}
	}

	/**
	 * 根据一个字段名，获取一组有可能成为 Setter 函数
	 * 
	 * @param fieldName
	 * @return 函数数组
	 */
	public Method[] findSetters(String fieldName)
	{
		String mName = "set" + StringUtils.capitalize(fieldName);
		List<Method> ms = new ArrayList<Method>();
		for (Method m : this.klass.getMethods())
			if (!Modifier.isStatic(m.getModifiers()) && (m.getParameterTypes().length == 1) && m.getName().equals(mName))
				ms.add(m);
		return ms.toArray(new Method[ms.size()]);
	}

	/**
	 * 获取一个字段。这个字段可以是当前类型或者其父类的私有字段。
	 * 
	 * @param name 字段名
	 * @return 字段
	 * @throws NoSuchFieldException
	 */
	public Field getField(String name) throws NoSuchFieldException
	{
		Class<?> cc = this.klass;
		while ((null != cc) && (cc != Object.class))
			try
			{
				return cc.getDeclaredField(name);
			}
			catch (NoSuchFieldException e)
			{
				cc = cc.getSuperclass();
			}
		throw new NoSuchFieldException(String.format("Can NOT find field [%s] in class [%s] and it's parents classes", name, this.klass.getName()));
	}

	/**
	 * 获取一个字段。这个字段必须声明特殊的注解，第一遇到的对象会被返回
	 * 
	 * @param ann 注解
	 * @return 字段
	 * @throws NoSuchFieldException
	 */
	public <AT extends Annotation> Field getField(Class<AT> ann) throws NoSuchFieldException
	{
		for (Field field : this.getFields())
			if (field.isAnnotationPresent(ann))
				return field;
		throw new NoSuchFieldException(String.format("Can NOT find field [@%s] in class [%s] and it's parents classes", ann.getName(), this.klass.getName()));
	}

	/**
	 * 获取一组声明了特殊注解的字段
	 * 
	 * @param ann 注解类型
	 * @return 字段数组
	 */
	public <AT extends Annotation> Field[] getFields(Class<AT> ann)
	{
		List<Field> fields = new LinkedList<Field>();
		for (Field f : this.getFields())
			if (f.isAnnotationPresent(ann))
				fields.add(f);
		return fields.toArray(new Field[fields.size()]);
	}

	private static boolean isIgnoredField(Field f)
	{
		return Modifier.isStatic(f.getModifiers()) || Modifier.isFinal(f.getModifiers()) || f.getName().startsWith("this$");
	}

	/**
	 * 获得所有的属性，包括私有属性。不包括 Object 的属性
	 */
	public Field[] getFields()
	{
		Class<?> cc = this.klass;
		Map<String, Field> map = new HashMap<String, Field>();
		while ((null != cc) && (cc != Object.class))
		{
			Field[] fs = cc.getDeclaredFields();
			for (int i = 0; i < fs.length; i++)
				if (!isIgnoredField(fs[i]) && !map.containsKey(fs[i].getName()))
					map.put(fs[i].getName(), fs[i]);
			cc = cc.getSuperclass();
		}
		return map.values().toArray(new Field[map.size()]);
	}

	/**
	 * 获取本类型所有的方法，包括私有方法。不包括 Object 的方法
	 */
	public Method[] getMethods()
	{
		Class<?> cc = this.klass;
		List<Method> list = new LinkedList<Method>();
		while ((null != cc) && (cc != Object.class))
		{
			Method[] ms = cc.getDeclaredMethods();
			for (Method element : ms)
				list.add(element);
			cc = cc.getSuperclass();
		}
		return list.toArray(new Method[list.size()]);
	}

	/**
	 * 获取当前对象，所有的方法，包括私有方法。递归查找至自己某一个父类为止 。
	 * <p>
	 * 并且这个按照名称，消除重复的方法。子类方法优先
	 * 
	 * @param top 截至的父类
	 * @return 方法数组
	 */
	public Method[] getAllDeclaredMethods(Class<?> top)
	{
		Class<?> cc = this.klass;
		Map<String, Method> map = new HashMap<String, Method>();
		while ((null != cc) && (cc != Object.class))
		{
			Method[] fs = cc.getDeclaredMethods();
			for (Method element : fs)
			{
				String key = element.getName() + Mirror.getParamDescriptor(element.getParameterTypes());
				if (!map.containsKey(key))
					map.put(key, element);
			}
			cc = cc.getSuperclass() == top ? null : cc.getSuperclass();
		}
		return map.values().toArray(new Method[map.size()]);
	}

	/**
	 * 相当于 getAllDeclaredMethods(Object.class)
	 * 
	 * @return 方法数组
	 */
	public Method[] getAllDeclaredMethodsWithoutTop()
	{
		return this.getAllDeclaredMethods(Object.class);
	}

	/**
	 * @return 所有静态方法
	 */
	public Method[] getStaticMethods()
	{
		List<Method> list = new LinkedList<Method>();
		for (Method m : this.klass.getMethods())
			if (Modifier.isStatic(m.getModifiers()) && Modifier.isPublic(m.getModifiers()))
				list.add(m);
		return list.toArray(new Method[list.size()]);
	}

	private static RuntimeException makeSetValueException(Class<?> type, String name, Object value, Exception e)
	{
		return new FailToSetValueException(String.format("Fail to set value [%s] to [%s]->[%s] because '%s'", value, type.getName(), name, e.getMessage()));
	}

	/**
	 * 为对象的一个字段设值。 不会调用对象的 setter，直接设置字段的值
	 * 
	 * @param obj 对象
	 * @param field 字段
	 * @param value 值。如果为 null，字符和数字字段，都会设成 0
	 * @throws FailToSetValueException
	 */
	public void setValue(Object obj, Field field, Object value) throws FailToSetValueException
	{
		if (!field.isAccessible())
			field.setAccessible(true);
		Mirror<?> me = Mirror.me(field.getType());
		if (null != value)
			try
			{
				if (!Mirror.me(value.getClass()).canCastToDirectly(me.getType()))
					value = Castors.me().castTo(value, field.getType());
			}
			catch (FailToCastObjectException e)
			{
				throw makeSetValueException(obj.getClass(), field.getName(), value, e);
			}
		else if (me.isNumber())
			value = 0;
		else if (me.isChar())
			value = (char) 0;
		try
		{
			field.set(obj, value);
		}
		catch (Exception e)
		{
			throw makeSetValueException(obj.getClass(), field.getName(), value, e);
		}
	}

	/**
	 * 为对象的一个字段设值。优先调用 setter 方法。
	 * 
	 * @param obj 对象
	 * @param fieldName 字段名
	 * @param value 值
	 * @throws FailToSetValueException
	 */
	public void setValue(Object obj, String fieldName, Object value) throws FailToSetValueException
	{
		try
		{
			this.getSetter(fieldName, value.getClass()).invoke(obj, value);
		}
		catch (Exception e)
		{
			try
			{
				Field field = this.getField(fieldName);
				this.setValue(obj, field, value);
			}
			catch (Exception e1)
			{
				throw makeSetValueException(obj.getClass(), fieldName, value, e1);
			}
		}
	}

	private static RuntimeException makeGetValueException(Class<?> type, String name)
	{
		return new FailToGetValueException(String.format("Fail to get value for [%s]->[%s]", type.getName(), name));
	}

	/**
	 * 不调用 getter，直接获得字段的值
	 * 
	 * @param obj 对象
	 * @param f 字段
	 * @return 字段的值。
	 * @throws FailToGetValueException
	 */
	public Object getValue(Object obj, Field f) throws FailToGetValueException
	{
		if (!f.isAccessible())
			f.setAccessible(true);
		try
		{
			return f.get(obj);
		}
		catch (Exception e)
		{
			throw makeGetValueException(obj.getClass(), f.getName());
		}
	}

	/**
	 * 优先通过 getter 获取字段值，如果没有，则直接获取字段值
	 * 
	 * @param obj 对象
	 * @param name 字段名
	 * @return 字段值
	 * @throws FailToGetValueException 既没发现 getter，又没有字段
	 */
	public Object getValue(Object obj, String name) throws FailToGetValueException
	{
		try
		{
			return this.getGetter(name).invoke(obj);
		}
		catch (Exception e)
		{
			try
			{
				return this.getValue(obj, this.getField(name));
			}
			catch (NoSuchFieldException e1)
			{
				throw makeGetValueException(obj.getClass(), name);
			}
		}
	}

	/**
	 * @return 对象类型
	 */
	public Class<T> getType()
	{
		return this.klass;
	}

	/**
	 * @return 对象提炼类型数组。从对象自身的类型到 Object，中间的继承关系中最有特点的几个类型
	 */
	public Class<?>[] extractTypes()
	{
		return this.typeExtractor.extract(this);
	}

	/**
	 * @return 获得外覆类
	 * @throws RuntimeException 如果当前类型不是原生类型，则抛出
	 */
	public Class<?> getWrapperClass()
	{
		if (!this.klass.isPrimitive())
		{
			if (this.isPrimitiveNumber() || this.is(Boolean.class) || this.is(Character.class))
				return this.klass;
			throw new ReflectException(String.format("Class '%s' should be a primitive class", this.klass.getName()));
		}
		if (this.is(int.class))
			return Integer.class;
		if (this.is(char.class))
			return Character.class;
		if (this.is(boolean.class))
			return Boolean.class;
		if (this.is(long.class))
			return Long.class;
		if (this.is(float.class))
			return Float.class;
		if (this.is(byte.class))
			return Byte.class;
		if (this.is(short.class))
			return Short.class;
		if (this.is(double.class))
			return Double.class;

		throw new ReflectException(String.format("Class [%s] has no wrapper class!", this.klass.getName()));
	}

	/**
	 * @return 获得外覆类，如果没有外覆类，则返回自身的类型
	 */
	public Class<?> getWrapper()
	{
		if (this.klass.isPrimitive())
			return this.getWrapperClass();
		return this.klass;
	}

	/**
	 * @return 如果当前类为内部类，则返回其外部类。否则返回 null
	 */
	public Class<?> getOuterClass()
	{
		if (Modifier.isStatic(this.klass.getModifiers()))
			return null;
		String name = this.klass.getName();
		int pos = name.lastIndexOf('$');
		if (pos == -1)
			return null;
		name = name.substring(0, pos);
		try
		{
			return Class.forName(name);
		}
		catch (ClassNotFoundException e)
		{
			return null;
		}
	}

	private static boolean doMatchMethodParamsType(Class<?>[] paramTypes, Class<?>[] methodArgTypes)
	{
		if ((paramTypes.length == 0) && (methodArgTypes.length == 0))
			return true;
		if (paramTypes.length == methodArgTypes.length)
		{
			for (int i = 0; i < paramTypes.length; i++)
				if (!Mirror.me(paramTypes[i]).canCastToDirectly((methodArgTypes[i])))
					return false;
			return true;
		}
		else if (paramTypes.length + 1 == methodArgTypes.length)
		{
			if (!methodArgTypes[paramTypes.length].isArray())
				return false;
			for (int i = 0; i < paramTypes.length; i++)
				if (!Mirror.me(paramTypes[i]).canCastToDirectly((methodArgTypes[i])))
					return false;
			return true;
		}
		return false;
	}

	/**
	 * 查找一个方法。匹配的很宽泛
	 * 
	 * @param name 方法名
	 * @param paramTypes 参数类型列表
	 * @return 方法
	 * @throws NoSuchMethodException
	 */
	public Method findMethod(String name, Class<?>... paramTypes) throws NoSuchMethodException
	{
		try
		{
			return this.klass.getMethod(name, paramTypes);
		}
		catch (NoSuchMethodException e)
		{
			for (Method m : this.klass.getMethods())
				if (m.getName().equals(name))
					if (doMatchMethodParamsType(paramTypes, m.getParameterTypes()))
						return m;
		}
		throw new NoSuchMethodException(String.format("Fail to find Method %s->%s with params:\n%s", this.klass.getName(), name, StringUtils.join(paramTypes)));
	}

	/**
	 * 根据名称和参数个数，查找一组方法
	 * 
	 * @param name 方法名
	 * @param argNumber 参数个数
	 * @return 方法数组
	 */
	public Method[] findMethods(String name, int argNumber)
	{
		List<Method> methods = new LinkedList<Method>();
		for (Method m : this.klass.getMethods())
			if (m.getName().equals(name))
				if (argNumber < 0)
					methods.add(m);
				else if (m.getParameterTypes().length == argNumber)
					methods.add(m);
		return methods.toArray(new Method[methods.size()]);
	}

	/**
	 * 根据返回值类型，以及参数类型，查找第一个匹配的方法
	 * 
	 * @param returnType 返回值类型
	 * @param paramTypes 参数个数
	 * @return 方法
	 * @throws NoSuchMethodException
	 */
	public Method findMethod(Class<?> returnType, Class<?>... paramTypes) throws NoSuchMethodException
	{
		for (Method m : this.klass.getMethods())
			if (returnType == m.getReturnType())
				if (paramTypes.length == m.getParameterTypes().length)
				{
					boolean noThisOne = false;
					for (int i = 0; i < paramTypes.length; i++)
						if (paramTypes[i] != m.getParameterTypes()[i])
						{
							noThisOne = true;
							break;
						}
					if (!noThisOne)
						return m;
				}
		throw new NoSuchMethodException(String.format("Can not find method in [%s] with return type '%s' and arguemtns \n'%s'!", this.klass.getName(), returnType.getName(), StringUtils.join(paramTypes)));

	}

	/**
	 * 一个方法的参数类型同一个给定的参数数组是否可以匹配
	 * 
	 * @param methodParamTypes 参数类型列表
	 * @param args 参数
	 * @return 匹配类型 .lang.MatchType
	 */
	public static MatchType matchParamTypes(Class<?>[] methodParamTypes, Object... args)
	{
		return matchParamTypes(methodParamTypes, evalToTypes(args));
	}

	/**
	 * 将一组对象，变成一组类型
	 * 
	 * @param args 对象数组
	 * @return 类型数组
	 */
	public static Class<?>[] evalToTypes(Object... args)
	{
		Class<?>[] types = new Class[args.length];
		int i = 0;
		for (Object arg : args)
			types[i++] = null == arg ? Object.class : arg.getClass();
		return types;
	}

	static Object evalArgToSameTypeRealArray(Object... args)
	{
		Object array = evalArgToRealArray(args);
		return array == args ? null : array;
	}

	/**
	 * 将一个 Object[] 数组，变成一个真正的数组 T[]
	 * 
	 * @param args 数组
	 * @return 新数组
	 */
	public static Object evalArgToRealArray(Object... args)
	{
		if ((null == args) || (args.length == 0) || (null == args[0]))
			return null;
		Object re = null;
		/*
		 * Check inside the arguments list, to see if all element is in same type
		 */
		Class<?> type = null;
		for (Object arg : args)
		{
			if (null == arg)
				break;
			if (null == type)
			{
				type = arg.getClass();
				continue;
			}
			if (arg.getClass() != type)
			{
				type = null;
				break;
			}
		}
		/*
		 * If all argument elements in same type, make a new Array by the Type
		 */
		if (type != null)
		{
			re = Array.newInstance(type, args.length);
			for (int i = 0; i < args.length; i++)
				Array.set(re, i, args[i]);
			return re;
		}
		return args;

	}

	/**
	 * 匹配一个函数声明的参数类型数组和一个调用参数数组
	 * 
	 * @param paramTypes 函数声明参数数组
	 * @param argTypes 调用参数数组
	 * @return 匹配类型
	 */
	public static MatchType matchParamTypes(Class<?>[] paramTypes, Class<?>[] argTypes)
	{
		int len = argTypes == null ? 0 : argTypes.length;
		if ((len == 0) && (paramTypes.length == 0))
			return MatchType.YES;
		if (paramTypes.length == len)
		{
			for (int i = 0; i < len; i++)
				if (!Mirror.me(argTypes[i]).canCastToDirectly((paramTypes[i])))
					return MatchType.NO;
			return MatchType.YES;
		}
		else if (len + 1 == paramTypes.length)
		{
			if (!paramTypes[len].isArray())
				return MatchType.NO;
			for (int i = 0; i < len; i++)
				if (!Mirror.me(argTypes[i]).canCastToDirectly((paramTypes[i])))
					return MatchType.NO;
			return MatchType.LACK;
		}
		return MatchType.NO;
	}

	/**
	 * 判断当前对象是否为一个类型。精确匹配，即使是父类和接口，也不相等
	 * 
	 * @param type 类型
	 * @return 是否相等
	 */
	public boolean is(Class<?> type)
	{
		return (null != type) && (this.klass == type);
	}

	/**
	 * 判断当前对象是否为一个类型。精确匹配，即使是父类和接口，也不相等
	 * 
	 * @param className 类型名称
	 * @return 是否相等
	 */
	public boolean is(String className)
	{
		return this.klass.getName().equals(className);
	}

	/**
	 * @param type 类型或接口名
	 * @return 当前对象是否为一个类型的子类，或者一个接口的实现类
	 */
	public boolean isOf(Class<?> type)
	{
		return type.isAssignableFrom(this.klass);
	}

	/**
	 * @return 当前对象是否为字符串
	 */
	public boolean isString()
	{
		return this.is(String.class);
	}

	/**
	 * @return 当前对象是否为CharSequence的子类
	 */
	public boolean isStringLike()
	{
		return CharSequence.class.isAssignableFrom(this.klass);
	}

	/**
	 * @return 当前对象是否为字符
	 */
	public boolean isChar()
	{
		return this.is(char.class) || this.is(Character.class);
	}

	/**
	 * @return 当前对象是否为枚举
	 */
	public boolean isEnum()
	{
		return this.klass.isEnum();
	}

	/**
	 * @return 当前对象是否为布尔
	 */
	public boolean isBoolean()
	{
		return this.is(boolean.class) || this.is(Boolean.class);
	}

	/**
	 * @return 当前对象是否为浮点
	 */
	public boolean isFloat()
	{
		return this.is(float.class) || this.is(Float.class);
	}

	/**
	 * @return 当前对象是否为双精度浮点
	 */
	public boolean isDouble()
	{
		return this.is(double.class) || this.is(Double.class);
	}

	/**
	 * @return 当前对象是否为整型
	 */
	public boolean isInt()
	{
		return this.is(int.class) || this.is(Integer.class);
	}

	/**
	 * @return 当前对象是否为整数（包括 int, long, short, byte）
	 */
	public boolean isIntLike()
	{
		return this.isInt() || this.isLong() || this.isShort() || this.isByte() || this.is(BigDecimal.class);
	}

	/**
	 * @return 当前对象是否为小数 (float, dobule)
	 */
	public boolean isDecimal()
	{
		return this.isFloat() || this.isDouble();
	}

	/**
	 * @return 当前对象是否为长整型
	 */
	public boolean isLong()
	{
		return this.is(long.class) || this.is(Long.class);
	}

	/**
	 * @return 当前对象是否为短整型
	 */
	public boolean isShort()
	{
		return this.is(short.class) || this.is(Short.class);
	}

	/**
	 * @return 当前对象是否为字节型
	 */
	public boolean isByte()
	{
		return this.is(byte.class) || this.is(Byte.class);
	}

	/**
	 * @param type 类型
	 * @return 否为一个对象的外覆类
	 */
	public boolean isWrpperOf(Class<?> type)
	{
		try
		{
			return Mirror.me(type).getWrapperClass() == this.klass;
		}
		catch (Exception e)
		{
		}
		return false;
	}

	/**
	 * @param type 目标类型
	 * @return 判断当前对象是否能直接转换到目标类型，而不产生异常
	 */
	public boolean canCastToDirectly(Class<?> type)
	{
		if ((this.klass == type) || type.isAssignableFrom(this.klass))
			return true;
		if (this.klass.isPrimitive() && type.isPrimitive())
			if (this.isPrimitiveNumber() && Mirror.me(type).isPrimitiveNumber())
				return true;
		try
		{
			return Mirror.me(type).getWrapperClass() == this.getWrapperClass();
		}
		catch (Exception e)
		{
		}
		return false;
	}

	/**
	 * @return 当前对象是否为原生的数字类型 （即不包括 boolean 和 char）
	 */
	public boolean isPrimitiveNumber()
	{
		return this.isInt() || this.isLong() || this.isFloat() || this.isDouble() || this.isByte() || this.isShort();
	}

	/**
	 * @return 当前对象是否为数字
	 */
	public boolean isNumber()
	{
		return Number.class.isAssignableFrom(this.klass) || (this.klass.isPrimitive() && !this.is(boolean.class) && !this.is(char.class));
	}

	/**
	 * @return 当前对象是否在表示日期或时间
	 */
	public boolean isDateTimeLike()
	{
		return Calendar.class.isAssignableFrom(this.klass) || java.util.Date.class.isAssignableFrom(this.klass) || java.sql.Date.class.isAssignableFrom(this.klass) || java.sql.Time.class.isAssignableFrom(this.klass);
	}

	@Override
	public String toString()
	{
		return this.klass.getName();
	}

	static Object[] blankArrayArg(Class<?>[] pts)
	{
		return (Object[]) Array.newInstance(pts[pts.length - 1].getComponentType(), 0);
	}

	/**
	 * 获取一个类的泛型参数数组，如果这个类没有泛型参数，返回 null
	 */
	public static Type[] getTypeParams(Class<?> klass)
	{
		if (klass == null)
			return null;
		Type superclass = klass.getGenericSuperclass();
		if ((superclass == null) || "java.lang.Object".equals(superclass.toString()))
			return null;
		if (superclass instanceof ParameterizedType)
			return ((ParameterizedType) superclass).getActualTypeArguments();
		return getTypeParams(klass.getSuperclass());
	}

	private static final Pattern PTN = Pattern.compile("(<)(.+)(>)");

	/**
	 * 获取一个字段的泛型参数数组，如果这个字段没有泛型，返回空数组
	 * 
	 * @param f 字段
	 * @return 泛型参数数组
	 */
	public static Class<?>[] getGenericTypes(Field f)
	{
		String gts = f.toGenericString();
		Matcher m = PTN.matcher(gts);
		if (m.find())
		{
			String s = m.group(2);
			String[] ss = StringUtils.split(s);
			if (ss.length > 0)
			{
				Class<?>[] re = new Class<?>[ss.length];
				try
				{
					for (int i = 0; i < ss.length; i++)
					{
						String className = ss[i];
						if (className.startsWith("?"))
							re[i] = Object.class;
						else
						{
							int pos = className.indexOf('<');
							if (pos < 0)
								re[i] = Class.forName(className);
							else
								re[i] = Class.forName(className.substring(0, pos));
						}
					}
					return re;
				}
				catch (ClassNotFoundException e)
				{
					throw new ReflectException("ClassNotFound", e);
				}
			}
		}
		return new Class<?>[0];
	}

	/**
	 * 获取一个类的某个一个泛型参数
	 * 
	 * @param klass 类
	 * @param index 参数下标 （从 0 开始）
	 * @return 泛型参数类型
	 */
	@SuppressWarnings("unchecked")
	public static <T> Class<T> getTypeParam(Class<?> klass, int index)
	{
		Type[] types = getTypeParams(klass);
		if ((index >= 0) && (index < types.length))
		{
			Type t = types[index];
			if (t instanceof Class<?>)
				return (Class<T>) t;
			throw new ReflectException(String.format("Type '%s' is not a Class", t.toString()));
		}
		throw new ReflectException(String.format("Class type param out of range %d/%d", index, types.length));
	}

	/**
	 * @param klass 类型
	 * @return 一个类型的包路径
	 */
	public static String getPath(Class<?> klass)
	{
		return klass.getName().replace('.', '/');
	}

	/**
	 * @param parameterTypes 函数的参数类型数组
	 * @return 参数的描述符
	 */
	public static String getParamDescriptor(Class<?>[] parameterTypes)
	{
		StringBuilder sb = new StringBuilder();
		sb.append('(');
		for (Class<?> pt : parameterTypes)
			sb.append(getTypeDescriptor(pt));
		sb.append(')');
		String s = sb.toString();
		return s;
	}

	/**
	 * @param method 方法
	 * @return 这个方法的描述符
	 */
	public static String getMethodDescriptor(Method method)
	{
		return getParamDescriptor(method.getParameterTypes()) + getTypeDescriptor(method.getReturnType());
	}

	/**
	 * @param c 构造函数
	 * @return 构造函数的描述符
	 */
	public static String getConstructorDescriptor(Constructor<?> c)
	{
		return getParamDescriptor(c.getParameterTypes()) + "V";
	}

	/**
	 * @param klass 类型
	 * @return 获得一个类型的描述符
	 */
	public static String getTypeDescriptor(Class<?> klass)
	{
		if (klass.isPrimitive())
			if (klass == void.class)
				return "V";
			else if (klass == int.class)
				return "I";
			else if (klass == long.class)
				return "J";
			else if (klass == byte.class)
				return "B";
			else if (klass == short.class)
				return "S";
			else if (klass == float.class)
				return "F";
			else if (klass == double.class)
				return "D";
			else if (klass == char.class)
				return "C";
			else
				/* if(klass == boolean.class) */
				return "Z";
		StringBuilder sb = new StringBuilder();
		if (klass.isArray())
			return sb.append('[').append(getTypeDescriptor(klass.getComponentType())).toString();
		return sb.append('L').append(Mirror.getPath(klass)).append(';').toString();
	}

	/**
	 * 查找包含某一个特殊注解的字段
	 * 
	 * @param type 类型
	 * @param ann 注解类型
	 * @return 字段，null 表示没有找到
	 */
	public static Field findField(Class<?> type, Class<? extends Annotation> ann)
	{
		Mirror<?> mirror = Mirror.me(type);
		for (Field f : mirror.getFields())
			if (f.isAnnotationPresent(ann))
				return f;
		return null;
	}

	/**
	 * It will find:
	 * <ol>
	 * <li>Default Constructor
	 * <li>Static Method without args
	 * <li>Constructor with one array arguments
	 * <li>Static Method with one array arguments
	 * </ol>
	 * 
	 * @throws InvocationTargetException
	 * @throws IllegalAccessException
	 * @throws InstantiationException
	 * @throws IllegalArgumentException
	 */
	@SuppressWarnings("unchecked")
	private T bornEvalNullArgs(Object[] args) throws IllegalArgumentException, InstantiationException, IllegalAccessException, InvocationTargetException
	{
		try
		{
			@SuppressWarnings("rawtypes")
			Constructor constructor = this.klass.getConstructor();
			return (T) constructor.newInstance(new Object[0]);
		}
		catch (Exception e)
		{
			Method[] sms = this.getStaticMethods();
			for (Method m : sms)
				if ((m.getReturnType() == this.klass) && (m.getParameterTypes().length == 0))
					return (T) m.invoke(null);
			// constructor with array input
			for (Constructor<?> cc : this.klass.getConstructors())
			{
				Class<?>[] pts = cc.getParameterTypes();
				if ((pts.length == 1) && pts[0].isArray())
				{
					args = new Object[1];
					args[0] = Mirror.blankArrayArg(pts);
					return (T) cc.newInstance(args);
				}
			}
			// static
			for (Method m : sms)
			{
				Class<?>[] pts = m.getParameterTypes();
				if ((m.getReturnType() == this.klass) && (m.getParameterTypes().length == 1) && pts[0].isArray())
				{
					args = new Object[1];
					args[0] = Mirror.blankArrayArg(pts);
					return (T) m.invoke(null, args);
				}
			}
			return null;
		}
	}

	/**
	 * It will find:
	 * <ol>
	 * <li>Constructor with same args
	 * <li>Constractor with args and the last one is array arguments
	 * <li>Static Method with same args
	 * <li>Static Method with args and the last one is array arguments
	 * <li>Try to find one constrcture with same number of args, and cast all args value
	 * <li>Try to find one static method with same number of args, and cast all args value
	 * </ol>
	 * 
	 * @throws InvocationTargetException
	 * @throws IllegalAccessException
	 * @throws IllegalArgumentException
	 * @throws InstantiationException
	 */

	@SuppressWarnings("unchecked")
	private T bornEvalWithArgs(Object[] args) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException, InstantiationException
	{
		Class<?>[] argTypes = Mirror.evalToTypes(args);
		Object dynaArg = evalArgToRealArray(args);

		for (Constructor<?> cc : this.klass.getConstructors())
		{
			Class<?>[] pts = cc.getParameterTypes();
			MatchType mt = Mirror.matchParamTypes(pts, argTypes);
			if (MatchType.YES == mt)
				return (T) cc.newInstance(args);
			else if (MatchType.LACK == mt)
			{
				args = Util.arrayLast(args, Mirror.blankArrayArg(pts));
				return (T) cc.newInstance(args);
			}
			else if ((null != dynaArg) && (pts.length == 1) && (pts[0] == dynaArg.getClass()))
				return (T) cc.newInstance(Mirror.evalArgToRealArray(args));
		}
		Method[] sms = this.getStaticMethods();
		for (Method m : sms)
		{
			Class<?>[] pts = m.getParameterTypes();
			MatchType mt = Mirror.matchParamTypes(pts, args);
			if (MatchType.YES == mt)
				return (T) m.invoke(null, args);
			else if (MatchType.LACK == mt)
			{
				args = Util.arrayLast(args, Mirror.blankArrayArg(pts));
				return (T) m.invoke(null, args);
			}
			else if ((null != dynaArg) && (pts.length == 1))
				if (pts[0] == dynaArg.getClass())
					return (T) m.invoke(null, Mirror.evalArgToRealArray(args));
		}
		// casting constructor
		try
		{
			for (Constructor<?> cc : this.klass.getConstructors())
			{
				Class<?>[] pts = cc.getParameterTypes();
				if (pts.length == args.length)
				{
					args = Util.array2ObjectArray(args, pts);
					return (T) cc.newInstance(args);
				}
			}
		}
		catch (Exception e)
		{
			return null;
		}
		// casting static methods
		try
		{
			for (Method m : sms)
			{
				Class<?>[] pts = m.getParameterTypes();
				if (pts.length == args.length)
				{
					args = Util.array2ObjectArray(args, pts);
					return (T) m.invoke(null, args);
				}
			}
		}
		catch (Exception e)
		{
			return null;
		}
		return null;
	}

}
